//#include <iostream>
//using namespace std;
#include "List.h"

void test()
{
	int a = 1;
	int& p1 = a;           // 正常引用左值
	const int b = 2;
	const int& p2 = b;
	
	// 右值引用 -> 不可取地址的变量用
	int&& c = 10;          // 正常引用右值

	const int& x1 = 2;     // 左引用引用右值     + const
	int&& x2 = move(a);    // 右引用引用左值     + move()函数
}


My_List::list<int> test_Right()
{
	My_List::list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	return (My_List::list<int>&&)lt;      // 把lt强转为右值
}

void func(const int& x)
{
	cout << "const 左值引用" << endl;
}

void func(int& x)
{
	cout << "左值引用" << endl;
}

void func(const int&& x)
{
	cout << "const 右值引用" << endl;
}

void func(int&& x)
{
	cout << "右值引用" << endl;
}

template<class T>
void test()
{
	//const T a = 0;
	// T a = 0;
	const T a = 0;

	func(move(a));

}

template<class T>
void test_forward(T&& a)     // 万能引用
{
	// forward -> 完美转发
	func(forward<T>(a));    // forward 对应参数之前的类型 
}


//int main()
//{
//	//My_List::list<int>ret = test_Right();
//	int a = 0;
//	const int b = 0;
//	int&& c = 0;       // c 接受的是右值，但是c自身是左值
//	const int&& d = 0;
//	// 因为传值之后具有退化性，右值全部退化为左值 这里就需要引入 forward
//	test_forward(a);
//	test_forward(b);
//	test_forward(move(c));
//	test_forward(move(d));
//	return 0;
//}


// 方法一: 查看可变模板参数类型
template<class T>
void Print(const T& value)
{
	// cout << typeid(value).name() << " ";
	cout << value << " ";
}

// 为了在编译时查看模板参数类型 用不知道长度的数组，它的长度在编译时确定
template<class ...Args>
void test_Arguments(Args&&... args)
{
	//int arr[] = { (Print(args),0)... };   // 这种数组类型长度是在编译时确定的，和可变模板参数相同
	int arr[] = { (cout << args << " ",0)... };
}



// 方法二: 递归
// 写出一个重载作为无参时候的截至条件
void Print1()
{
	cout << endl;
}

template<class T, class ...Args>
void Print1(const T& value, Args&&... args)
{
	cout << value << " ";
	Print1(args...);
}

template<class ...Args>
void test_Arguments1(Args&&... args)
{
	Print1(args...);
}

int main5()
{
	// 作为可变参数模板 可传0 - 任意个模板参数
	test_Arguments(1, "abcd", 1.1);
	//test_Arguments1(1, "abcd", 1.1);

	list<string> lt;
	lt.emplace_back("aaaaaaa");
	return 0;
}

#include "string.h"

//int main()
//{
//	//My_List::list<Mystring::string> lt;
//	//Mystring::string s1 = "111111111";
//	//lt.push_back(s1);
//	//lt.push_back("111111111");
//	Mystring::string s("11111111");
//
//	Mystring::string s1 = s;
//	Mystring::string s2(move(s));
//
//
//	return 0;
//}


Mystring::string test_moveassignment()
{
	Mystring::string ret;
	ret += 'x';
	return ret;
}

//int main()
//{
//	Mystring::string s1;
//	s1 = test_moveassignment();     // 移动赋值编译器也做了优化 不过优化较小 只是中间没有产生临时变量
//									// 直接走的移动赋值
//
//	return 0;
//}

#include <algorithm>
#include <vector>
#include <functional>
// lambda 使用方法
struct Goods
{
	double _price;
	double _evaluate;
	string _name;
	Goods(const string& name, double price, double evaluate)
		:_price(price)
		, _evaluate(evaluate)
		,_name(name)
	{}
};


int main1()
{
	vector<Goods> v= { {"榴莲",10.99,4.6},{"苹果", 2.0,4.5}, {"芝士",15.99,4.7},{"奶酪",20.99,4.8} };
	sort(v.begin(), v.end(), [](Goods& g1, Goods& g2)->bool     // 根据价格排序
		{
			return g1._price > g2._price;
		});
	sort(v.begin(), v.end(), [](Goods& g1, Goods& g2)     // 根据名字排序
		{
			return g1._name > g2._name;
		});
	sort(v.begin(), v.end(), [](Goods& g1, Goods& g2)     // 根据评价排序
		{
			return g1._evaluate > g2._evaluate;
		});

	// function 包装函数
	function<bool(Goods& g1, Goods& g2)> f1 = [](Goods& g1, Goods& g2)->bool     // 根据价格排序
		{
			return g1._price > g2._price;
		};
	function<bool(Goods& g1, Goods& g2)> f2 = [](Goods& g1, Goods& g2)->bool     // 根据价格排序
		{
			return g1._name > g2._name;
		};
	sort(v.begin(), v.end(), f2);
	return 0;
}

// lambda 不同捕捉方法
int main2()
{
	int a = 0, b = 1, c = 2, d = 3;
	auto f1 = [&]      // 引用传参可以修改参数
		{
			b = c = d = 3;
			return ++a + b + c + d;
		};
	cout << f1() << endl;

	auto f2 = [=]()mutable      // 传值传参不可以修改参数
		{                       // 虽然 mutable 取消了const对参数的修饰，但是传值传参无法对外部参数造成影响
			return a + b + c + d;
		};
	cout << f2() << endl;
	auto f3 = [&a, b]         // 返回值是 void 类型的  并且混合使用
		{
			++a;
			cout << a << " " << b << endl;
		};
	f3();
	return 0;
}

struct myless
{
	bool operator()(Goods& g1, Goods& g2)  // 根据名字排序的仿函数
	{
		return g1._name > g2._name;
	}
};

int Add(int x, int y)
{
	return x + y;
}

// function 包装器    -> 包装 1、lambda 类型匿名函数  2、包装普通函数   3、包装仿函数 
// 使用时相当于仿函数的方式使用
int main3()
{
	vector<Goods> v = { {"榴莲",10.99,4.6},{"苹果", 2.0,4.5}, {"芝士",15.99,4.7},{"奶酪",20.99,4.8} };
	function<bool(Goods& g1, Goods& g2)> f1 = myless();     // 包装仿函数
	sort(v.begin(), v.end(), f1);
	function<bool(Goods& g1, Goods& g2)> f2 = [](Goods& g1, Goods& g2)->bool     // 包装lambda 匿名函数
		{
			return g1._price > g2._price;
		};
	sort(v.begin(), v.end(), f2);

	function<int(int, int)> f3 = Add;       // 包装普通函数
	cout << f3(1, 2) << endl;

	return 0;
}

// bind 绑定的使用方法
int main4()
{
	function<double(int,double,double)> f1 = [](int year, double money, double rate)->double         // 计算本金的利息
		{
			double mymoney = money;
			for (int i = 1; i <= year; i++)
			{
				money += money * rate;
			}
			return money - mymoney;
		};

	// 对年份和利率进行绑定   只需要传一个money的参数即可
	auto f_3_0025 = bind(f1, 3, placeholders::_1, 0.025);
	auto f_5_0028 = bind(f1, 5, placeholders::_1, 0.028);
	auto f_10_0028 = bind(f1, 10, placeholders::_1, 0.03);
	auto f_20_0028 = bind(f1, 20, placeholders::_1, 0.032);
	cout << f_3_0025(10000) << endl;
	cout << f_5_0028(10000) << endl;
	cout << f_10_0028(10000) << endl;
	cout << f_20_0028(10000) << endl;


	return 0;
}


// emplace_back 对于左值效率更高 减少了左值的拷贝
int main()
{
	list<Mystring::string> lt;
	Mystring::string s = "11111111";
	Mystring::string s2 = "11111111";
	My_List::list<Mystring::string> lt1;

	lt.emplace_back(move(s));
	lt1.emplace_back(move(s2));
	lt1.emplace_back("2222222222");        // 用参数包进行传递 减少中间商，最后再解析传递
	//My_List::list<pair<Mystring::string,int>> lt1;
	//lt.emplace_back( s,1 );

	My_List::list<pair<Mystring::string,int>> lt2;
	lt2.emplace_back("苹果", 2);      // 对于pair类型不需要直接构造pair类型就可以使用 更方便 (改造方法)
	lt2.emplace_back(make_pair( "苹果",1 ));     // 原先写法

	return 0;
}